#include "adc.h"
  
volatile	u32		ADC_DualConvertedValueTab[BufferLength];
volatile	u16		ADC1_RegularConvertedValueTab[BufferLength];
volatile	u16		ADC2_RegularConvertedValueTab[BufferLength];
static		u16		hPhaseAOffset;
static 		u16		hPhaseBOffset;
 
void ADC_DMA_Init(void)
{
    u8 bIndex;
	
    GPIO_InitTypeDef	GPIO_InitStructure;
    ADC_InitTypeDef		ADC_InitStructure;
    DMA_InitTypeDef   DMA_InitStructure;
    NVIC_InitTypeDef	NVIC_InitStructure;
	
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);                    //ADCCLK = PCLK2/6=72M/6=12MHz，ADC最大频率不能超过14MHz
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);    //DMA1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);	
 
    GPIO_StructInit(&GPIO_InitStructure);             //Fills each GPIO_InitStruct member with its default value    
    GPIO_InitStructure.GPIO_Pin = PHASE_A_GPIO_PIN;     
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(PHASE_A_GPIO_PORT, &GPIO_InitStructure);
 
    GPIO_InitStructure.GPIO_Pin = PHASE_B_GPIO_PIN;      
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(PHASE_B_GPIO_PORT, &GPIO_InitStructure);
 
    //设置DMA1，用于自动存储ADC1和ADC2规则通道的转换值
    DMA_DeInit(DMA1_Channel1);
    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;                  //ADC数据寄存器地址(源地址)
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_DualConvertedValueTab;  //转换值存储地址(目标地址)
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                           //从外设到内存
    DMA_InitStructure.DMA_BufferSize = BufferLenght;                             //传输大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;             //外设地址不增
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                      //内存地址自增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;      //外设数据单位(每次传输32位)
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;              //内存数据单位(每次传输32位)
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                              //循环模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                          //本DMA通道优先级(用了多个通道时，本参数才有效果)
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                 //没有使用内存到内存的传输
    DMA_Init(DMA1_Channel1,&DMA_InitStructure);
	
    DMA_ClearITPendingBit(DMA1_IT_TC1);                //清除通道1传输完成中断          
    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);    //打开通道1传输完成中断	
    DMA_Cmd(DMA1_Channel1, ENABLE);                    //使能DMA1
 
/****使用双ADC模式，ADC1为主，ADC2为从。当ADC转换配置成由外部事件触发时，用户必须设置成仅触发主ADC，从ADC设置成软件触发，这样可以防止意外的触发从转换。
但是，主和从ADC的外部触发必须同时被激活，要调用 ADC_ExternalTrigConvCmd(ADC2, ENABLE);//ADC2外部触发使能****/
    ADC_DeInit(ADC1);
    ADC_DeInit(ADC2);
    ADC_StructInit(&ADC_InitStructure);
    ADC_InitStructure.ADC_Mode = ADC_Mode_RegInjecSimult;  //ADC1工作在混合同步规则及注入模式
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;           //轮流采集各个通道的值
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;     //连续转换模式，触发后就会一直转换
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换触发信号选择，使用一个软件信号触发ADC1
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //数据右对齐，ADC是12位，要存到DR寄存器的高16位或低16位，就有左右对齐问题，决定了高4位无效或低4位无效
    ADC_InitStructure.ADC_NbrOfChannel = 1;	               //要进行ADC转换的通道数：BUS_SHUNT(母线电压)+BREAK_SHUNT(刹车电阻电流)+Chip Temp(MCU温度)
    ADC_Init(ADC1, &ADC_InitStructure);
 
    ADC_DMACmd(ADC1, ENABLE);                              //使能ADC1的DMA
 
    ADC_StructInit(&ADC_InitStructure);
    ADC_InitStructure.ADC_Mode = ADC_Mode_RegInjecSimult;  //ADC2工作在混合同步规则及注入模式
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;           
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;     //连续转换模式，触发后就会一直转换
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  //转换触发信号选择，由软件给信号触发，双ADC模式的从ADC必须设置为软件触发
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 3;                //要进行ADC转换的通道数：POT1(电位器)+AIN0(备用)+AIN1(备用)
    ADC_Init(ADC2, &ADC_InitStructure);
    ADC_ExternalTrigConvCmd(ADC2, ENABLE);                 //ADC2外部触发使能，双ADC模式的从ADC必须要用这条语句
	
    ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5);           //MCU温度
    ADC_RegularChannelConfig(ADC2, POT1_VOLT_FDBK_CHANNEL, 1, ADC_SampleTime_239Cycles5);   //电位器
    ADC_RegularChannelConfig(ADC2, AIN0_VOLT_FDBK_CHANNEL, 2, ADC_SampleTime_239Cycles5);   //备用
    ADC_RegularChannelConfig(ADC2, AIN1_VOLT_FDBK_CHANNEL, 3, ADC_SampleTime_239Cycles5);	//备用 
	
    ADC_Cmd(ADC1, ENABLE);	                           //ADC1使能
    ADC_TempSensorVrefintCmd(ENABLE);                  //开启MCU内存温度传感器及Vref通道
	
    ADC_ResetCalibration(ADC1);                        //复位校准寄存器
    while(ADC_GetResetCalibrationStatus(ADC1));       //等待校准寄存器复位完成
    ADC_StartCalibration(ADC1);                        //ADC1开始校准
    while(ADC_GetCalibrationStatus(ADC1));            //等待校准完成
 
    ADC_Cmd(ADC2, ENABLE);                             //ADC2使能
    ADC_ResetCalibration(ADC2);                        //复位校准寄存器
    while(ADC_GetResetCalibrationStatus(ADC2));       //等待校准寄存器复位完成
    ADC_StartCalibration(ADC2);                        //ADC2开始校准  
    while(ADC_GetCalibrationStatus(ADC2));	           //等待校准完成
 
/**** 获取A、B相零电流值，下面是临时配置 ****/
    ADC_InjectedSequencerLengthConfig(ADC1,2);         //设置ADC1注入组通道数量
    ADC_ITConfig(ADC1, ADC_IT_JEOC, DISABLE);          //关闭注入组转换完成中断
    hPhaseAOffset=0;                                   //A相零电流值
    hPhaseBOffset=0;                                   //B相零电流值
    ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_None);        //ADC1注入组转换的触发信号选择,注入组转换由软件触发
    ADC_ExternalTrigInjectedConvCmd(ADC1,ENABLE);                                    //使能外部信号触发注入组转换的功能
    ADC_InjectedChannelConfig(ADC1, PHASE_A_ADC_CHANNEL,1,ADC_SampleTime_7Cycles5);  //配置ADC1的注入组通道，设置它们的转化顺序和采样时间
    ADC_InjectedChannelConfig(ADC1, PHASE_B_ADC_CHANNEL,2,ADC_SampleTime_7Cycles5);  //A相电流和B相电流
 
    ADC_ClearFlag(ADC1, ADC_FLAG_JEOC);                    //清除注入组转换完成中断标志
    ADC_SoftwareStartInjectedConvCmd(ADC1,ENABLE);         //给一个软件触发信号，开始注入组转换
 
    for(bIndex=16; bIndex !=0; bIndex--)
    {
        while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_JEOC)) { }  //等待注入组转换完成  
 
        //求Q1.15格式的零电流值，16个（零电流值/8）的累加，把最高符号位溢出。
        hPhaseAOffset += (ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1)>>3);  //注入组左对齐，数据要右移3位才是真实数据
        hPhaseBOffset += (ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_2)>>3);
        ADC_ClearFlag(ADC1, ADC_FLAG_JEOC);                                                //清除注入组转换完成中断标志 
        ADC_SoftwareStartInjectedConvCmd(ADC1,ENABLE);                                     //给一个软件触发信号，开始注入组转换
    }
/**** 获取A、B相零电流值的临时配置使用结束，下面恢复ADC1的正常配置 ****/
 
    ADC_InjectedChannelConfig(ADC1, PHASE_A_ADC_CHANNEL,  1, ADC_SampleTime_7Cycles5);     //A相电流
    ADC_InjectedChannelConfig(ADC1, BUS_VOLT_FDBK_CHANNEL,2, ADC_SampleTime_7Cycles5);     //母线电压值
    ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_T1_TRGO);           //ADC1注入组转换的触发信号选择,注入组转换由TIM1的TRGO触发
    ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE);                                               //这里才能打开注入组转换完成中断	
 
    ADC_InjectedSequencerLengthConfig(ADC2,2);        //设置ADC2注入组通道数量
    ADC_InjectedChannelConfig(ADC2, PHASE_B_ADC_CHANNEL, 1,ADC_SampleTime_7Cycles5);       //B相电流                    
    ADC_InjectedChannelConfig(ADC2, TEMP_FDBK_CHANNEL,   2,ADC_SampleTime_7Cycles5);       //散热器温度                      
    ADC_ExternalTrigInjectedConvCmd(ADC2,ENABLE);	  //使能外部信号触发注入组转换的功能
	
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	  //4个抢先级、4个子优先级
 
    NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
 
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
 
//    ADC_ExternalTrigConvCmd(ADC1, ENABLE);   //ADC1外部触发使能，如果ADC的触发信号是外部就要调用
//    ADC_ExternalTrigConvCmd(ADC2, ENABLE);   //ADC2外部触发使能
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);    //给主ADC一个软件触发信号，之后ADC就会一直转换下去
}
 
u16 h_ADCBusvolt;
u16 h_ADCTemp;
u16 h_ADCPhase_A;
u16 h_ADCPhase_B;

void ADC1_2_IRQHandler(void)		//AD中断有三种情况：AD_EOC、AD_JEOC、AD_AWD
{	
	if((ADC1->SR & ADC_FLAG_JEOC) == ADC_FLAG_JEOC) 
	{
		ADC1->SR = ~(u32)ADC_FLAG_JEOC;           //清除注入组转换完成中断标志           
		
		//获取散热器温度和母线电压值，做出相应的处理
		h_ADCBusvolt=ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_2);  //母线电压
		
		//获取两相电流值，进行FOC运算
		h_ADCPhase_A=ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1);     //散热器温度
		h_ADCPhase_B=ADC_GetInjectedConversionValue(ADC2,ADC_InjectedChannel_1);  //母线电压		
	}
}
 
void DMA1_Channel1_IRQHandler(void)
{
	u8 i,j=0;
 
	if(DMA_GetITStatus(DMA1_IT_TC1))
	{
		DMA_ClearITPendingBit(DMA1_IT_GL1);    //清除DMA通道1传输完成中断
		for(i=0;i<BufferLenght;i++)
		{
			ADC1_RegularConvertedValueTab[j++] = (uint16_t)(ADC_DualConvertedValueTab[i]>>4);   //ADC1规则组左对齐，要右移4位
		}
		//ADC1_RegularConvertedValueTab[0]是MCU温度，ADC1_RegularConvertedValueTab[1]是刹车电阻电流，ADC1_RegularConvertedValueTab[2]是母线电流		
		j = 0;
 
		for(i=0;i<BufferLenght;i++)
		{
			ADC2_RegularConvertedValueTab[j++] = (uint16_t)(ADC_DualConvertedValueTab[i] >> 20);//ADC2规则组左对齐，要右移20位
		}
		//ADC2_RegularConvertedValueTab[0]是电位器，ADC2_RegularConvertedValueTab[1]是备用，ADC2_RegularConvertedValueTab[2]是备用	
	}
}
